import logging
from typing import List, Dict, Any
from datetime import datetime, timedelta
import threading
import time
import queue

from app.data_collection.news_crawler import NewsCrawler
from app.data_collection.weibo_crawler import WeiboCrawler
from app.data_collection.crawler import WebCrawler
from app.data_processing.sentiment_analyzer import SentimentAnalyzer
from app import db
from app.models import Article, SocialMediaPost, Keyword, Alert, SentimentHistory

class DataCollector:
    def __init__(self, api_key: str = None):
        self.logger = logging.getLogger(__name__)
        self.news_crawler = NewsCrawler()
        self.weibo_crawler = WeiboCrawler()
        self.web_crawler = WebCrawler()
        self.analyzer = SentimentAnalyzer(api_key=api_key)
        
        # 任务队列
        self.task_queue = queue.Queue()
        self.is_collecting = False
        self.collection_thread = None
    
    def collect_news(self, source: str = 'sina') -> List[Dict]:
        """
        采集新闻数据
        
        Args:
            source: 新闻源
            
        Returns:
            处理后的新闻数据
        """
        try:
            news_items = self.news_crawler.fetch_news_list(source)
            processed_items = []
            
            for item in news_items:
                # 分析情感
                sentiment = self.analyzer.analyze_sentiment(item.get('title', '') + ' ' + item.get('summary', ''))
                
                # 提取关键词
                keywords = self.analyzer.extract_keywords(item.get('title', '') + ' ' + item.get('summary', ''))
                
                # 添加分析结果
                item['sentiment'] = sentiment
                item['keywords'] = keywords
                
                processed_items.append(item)
                
                # 保存到数据库
                self._save_news_to_db(item)
            
            return processed_items
            
        except Exception as e:
            self.logger.error(f"采集新闻数据失败: {str(e)}")
            return []
    
    def collect_weibo(self, keyword: str) -> List[Dict]:
        """
        采集微博数据
        
        Args:
            keyword: 关键词
            
        Returns:
            处理后的微博数据
        """
        try:
            weibo_posts = self.weibo_crawler.fetch_weibo_by_keyword(keyword)
            processed_posts = []
            
            for post in weibo_posts:
                # 分析情感
                sentiment = self.analyzer.analyze_sentiment(post.get('content', ''))
                
                # 提取关键词
                keywords = self.analyzer.extract_keywords(post.get('content', ''))
                
                # 添加分析结果
                post['sentiment'] = sentiment
                post['keywords'] = keywords
                
                processed_posts.append(post)
                
                # 保存到数据库
                self._save_social_post_to_db(post)
            
            return processed_posts
            
        except Exception as e:
            self.logger.error(f"采集微博数据失败: {str(e)}")
            return []
    
    def collect_from_url(self, url: str) -> Dict:
        """
        从URL采集数据
        
        Args:
            url: 网页URL
            
        Returns:
            处理后的数据
        """
        try:
            news_items = self.web_crawler.fetch_news(url)
            processed_items = []
            
            for item in news_items:
                # 分析情感
                sentiment = self.analyzer.analyze_sentiment(item.get('title', '') + ' ' + item.get('content', ''))
                
                # 提取关键词
                keywords = self.analyzer.extract_keywords(item.get('title', '') + ' ' + item.get('content', ''))
                
                # 添加分析结果
                item['sentiment'] = sentiment
                item['keywords'] = keywords
                
                processed_items.append(item)
                
                # 保存到数据库
                self._save_news_to_db(item)
            
            return {
                'url': url,
                'items': processed_items,
                'count': len(processed_items)
            }
            
        except Exception as e:
            self.logger.error(f"从URL采集数据失败: {str(e)}")
            return {'url': url, 'items': [], 'count': 0, 'error': str(e)}
    
    def start_collection_task(self, task_type: str, params: Dict) -> str:
        """
        启动数据采集任务
        
        Args:
            task_type: 任务类型，支持 'news', 'weibo', 'url'
            params: 任务参数
            
        Returns:
            任务ID
        """
        task_id = f"{task_type}_{int(time.time())}"
        task = {
            'id': task_id,
            'type': task_type,
            'params': params,
            'status': 'pending',
            'created_at': datetime.now().isoformat()
        }
        
        self.task_queue.put(task)
        
        # 如果没有采集线程在运行，启动一个
        if not self.is_collecting or (self.collection_thread and not self.collection_thread.is_alive()):
            self.start_collection_thread()
        
        return task_id
    
    def start_collection_thread(self):
        """启动采集线程"""
        self.is_collecting = True
        self.collection_thread = threading.Thread(target=self._collection_worker)
        self.collection_thread.daemon = True
        self.collection_thread.start()
    
    def stop_collection_thread(self):
        """停止采集线程"""
        self.is_collecting = False
        if self.collection_thread and self.collection_thread.is_alive():
            self.collection_thread.join(timeout=2.0)
    
    def _collection_worker(self):
        """采集工作线程"""
        while self.is_collecting:
            try:
                # 获取任务，如果队列为空，等待1秒
                try:
                    task = self.task_queue.get(timeout=1.0)
                except queue.Empty:
                    continue
                
                # 更新任务状态
                task['status'] = 'processing'
                
                # 根据任务类型执行不同的采集
                if task['type'] == 'news':
                    source = task['params'].get('source', 'sina')
                    self.collect_news(source)
                elif task['type'] == 'weibo':
                    keyword = task['params'].get('keyword', '')
                    self.collect_weibo(keyword)
                elif task['type'] == 'url':
                    url = task['params'].get('url', '')
                    self.collect_from_url(url)
                
                # 更新任务状态
                task['status'] = 'completed'
                task['completed_at'] = datetime.now().isoformat()
                
                # 标记任务完成
                self.task_queue.task_done()
                
            except Exception as e:
                self.logger.error(f"采集工作线程异常: {str(e)}")
                time.sleep(5)  # 出错后等待一段时间再继续
    
    def _save_news_to_db(self, news_item: Dict):
        """保存新闻到数据库"""
        try:
            # 检查是否已存在
            existing = Article.query.filter_by(url=news_item.get('url')).first()
            if existing:
                return
            
            # 创建新文章
            article = Article(
                title=news_item.get('title', ''),
                content=news_item.get('content', '') or news_item.get('summary', ''),
                url=news_item.get('url', ''),
                source=news_item.get('source', ''),
                sentiment=news_item.get('sentiment', '中性'),
                published_at=datetime.fromisoformat(news_item.get('publish_time')) if news_item.get('publish_time') else datetime.now()
            )
            
            # 设置关键词
            if news_item.get('keywords'):
                article.set_keywords(news_item['keywords'])
                
                # 更新关键词频率
                for word in news_item['keywords']:
                    keyword = Keyword.query.filter_by(word=word).first()
                    if keyword:
                        keyword.frequency += 1
                        keyword.last_updated = datetime.now()
                    else:
                        keyword = Keyword(word=word, frequency=1)
                        db.session.add(keyword)
            
            db.session.add(article)
            db.session.commit()
            
            # 更新情感统计
            self._update_sentiment_stats(news_item.get('sentiment', '中性'))
            
            # 检查预警
            self._check_alerts(news_item)
            
        except Exception as e:
            db.session.rollback()
            self.logger.error(f"保存新闻到数据库失败: {str(e)}")
    
    def _save_social_post_to_db(self, post: Dict):
        """保存社交媒体帖子到数据库"""
        try:
            # 检查是否已存在
            existing = SocialMediaPost.query.filter_by(url=post.get('url')).first()
            if existing:
                return
            
            # 创建新帖子
            social_post = SocialMediaPost(
                platform=post.get('platform', ''),
                content=post.get('content', ''),
                author=post.get('author', ''),
                url=post.get('url', ''),
                sentiment=post.get('sentiment', '中性'),
                location=post.get('location', ''),
                published_at=datetime.fromisoformat(post.get('publish_time')) if post.get('publish_time') else datetime.now()
            )
            
            # 设置关键词
            if post.get('keywords'):
                social_post.set_keywords(post['keywords'])
                
                # 更新关键词频率
                for word in post['keywords']:
                    keyword = Keyword.query.filter_by(word=word).first()
                    if keyword:
                        keyword.frequency += 1
                        keyword.last_updated = datetime.now()
                    else:
                        keyword = Keyword(word=word, frequency=1)
                        db.session.add(keyword)
            
            db.session.add(social_post)
            db.session.commit()
            
            # 更新情感统计
            self._update_sentiment_stats(post.get('sentiment', '中性'))
            
            # 检查预警
            self._check_alerts(post)
            
        except Exception as e:
            db.session.rollback()
            self.logger.error(f"保存社交媒体帖子到数据库失败: {str(e)}")
    
    def _update_sentiment_stats(self, sentiment: str):
        """更新情感统计"""
        try:
            today = datetime.now().date()
            stats = SentimentHistory.query.filter_by(date=today).first()
            
            if not stats:
                stats = SentimentHistory(date=today)
                db.session.add(stats)
            
            if sentiment == '正面':
                stats.positive_count += 1
            elif sentiment == '负面':
                stats.negative_count += 1
            else:
                stats.neutral_count += 1
            
            db.session.commit()
            
        except Exception as e:
            db.session.rollback()
            self.logger.error(f"更新情感统计失败: {str(e)}")
    
    def _check_alerts(self, item: Dict):
        """检查是否触发预警"""
        try:
            # 获取所有预警设置
            alerts = Alert.query.all()
            
            for alert in alerts:
                # 检查关键词是否在内容中
                keyword = alert.keyword
                content = ''
                
                if 'title' in item and item['title']:
                    content += item['title'] + ' '
                
                if 'content' in item and item['content']:
                    content += item['content']
                elif 'summary' in item and item['summary']:
                    content += item['summary']
                
                if keyword in content:
                    # 检查阈值
                    # 这里简化处理，实际应用中可能需要更复杂的逻辑
                    # 例如统计一段时间内包含关键词的文章数量
                    
                    # 如果需要发送邮件通知
                    if alert.email_notification and alert.email:
                        self._send_alert_email(alert, item)
            
        except Exception as e:
            self.logger.error(f"检查预警失败: {str(e)}")
    
    def _send_alert_email(self, alert: Alert, item: Dict):
        """发送预警邮件"""
        # 这里应该实现发送邮件的逻辑
        # 简化处理，仅记录日志
        self.logger.info(f"发送预警邮件: 关键词 '{alert.keyword}' 触发预警，发送到 {alert.email}")
        self.logger.info(f"预警内容: {item.get('title', '')} - {item.get('source', '')}") 